package com.ruoyi.business.alarm.service.impl;

import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.ruoyi.business.alarm.constant.DoorAlarmConstants;
import com.ruoyi.business.alarm.mapper.DoorAlarmLogMapper;
import com.ruoyi.business.alarm.domain.DoorAlarmLog;
import com.ruoyi.business.alarm.domain.DoorStatusInfo;
import com.ruoyi.business.alarm.service.IDoorAlarmLogService;
import com.ruoyi.business.workshop.service.WorkshopManagementService;
import com.ruoyi.business.workshop.dto.WorkshopSlotDTO;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.business.alarm.websocket.AlarmWebSocketService;
/**
 * 门报警日志Service业务层处理
 * 
 * @author ruoyi
 * @date 2024-01-01
 */
@Service("doorAlarmLogService")
public class DoorAlarmLogServiceImpl implements IDoorAlarmLogService 
{
    private static final Logger log = LoggerFactory.getLogger(DoorAlarmLogServiceImpl.class);
    
    @Autowired
    private DoorAlarmLogMapper doorAlarmLogMapper;
    
    @Autowired
    private RedisCache redisCache;
    
    @Autowired
    private ApplicationContext applicationContext;
    
    @Autowired
    private WorkshopManagementService workshopManagementService;
    
    @Autowired
    private AlarmWebSocketService alarmWebSocketService;
    
    /**
     * 获取当前Service的代理对象，用于调用异步方法
     */
    private IDoorAlarmLogService getSelf() {
        try {
            // 优先通过Bean名称获取（返回Object，然后转换为接口类型）
            Object bean = applicationContext.getBean("doorAlarmLogService");
            if (bean instanceof IDoorAlarmLogService) {
                return (IDoorAlarmLogService) bean;
            }
        } catch (Exception e1) {
            // 忽略，继续尝试其他方式
        }
        
        try {
            // 通过接口类型获取（最可靠的方式）
            return applicationContext.getBean(IDoorAlarmLogService.class);
        } catch (Exception e2) {
            log.error("获取IDoorAlarmLogService Bean失败", e2);
            throw new RuntimeException("无法获取IDoorAlarmLogService Bean，请检查Spring配置", e2);
        }
    }

    /**
     * 查询门报警日志
     * 
     * @param alarmId 门报警日志主键
     * @return 门报警日志
     */
    @Override
    public DoorAlarmLog selectDoorAlarmLogByAlarmId(Long alarmId)
    {
        return doorAlarmLogMapper.selectDoorAlarmLogByAlarmId(alarmId);
    }

    /**
     * 查询门报警日志列表
     * 
     * @param doorAlarmLog 门报警日志
     * @return 门报警日志
     */
    @Override
    public List<DoorAlarmLog> selectDoorAlarmLogList(DoorAlarmLog doorAlarmLog)
    {
        return doorAlarmLogMapper.selectDoorAlarmLogList(doorAlarmLog);
    }

    /**
     * 新增门报警日志
     * 
     * @param doorAlarmLog 门报警日志
     * @return 结果
     */
    @Override
    public int insertDoorAlarmLog(DoorAlarmLog doorAlarmLog)
    {
        doorAlarmLog.setCreateTime(new Date());
        return doorAlarmLogMapper.insertDoorAlarmLog(doorAlarmLog);
    }

    /**
     * 修改门报警日志
     * 
     * @param doorAlarmLog 门报警日志
     * @return 结果
     */
    @Override
    public int updateDoorAlarmLog(DoorAlarmLog doorAlarmLog)
    {
        doorAlarmLog.setUpdateTime(new Date());
        return doorAlarmLogMapper.updateDoorAlarmLog(doorAlarmLog);
    }

    /**
     * 批量删除门报警日志
     * 
     * @param alarmIds 需要删除的门报警日志主键
     * @return 结果
     */
    @Override
    public int deleteDoorAlarmLogByAlarmIds(Long[] alarmIds)
    {
        return doorAlarmLogMapper.deleteDoorAlarmLogByAlarmIds(alarmIds);
    }

    /**
     * 删除门报警日志信息
     * 
     * @param alarmId 门报警日志主键
     * @return 结果
     */
    @Override
    public int deleteDoorAlarmLogByAlarmId(Long alarmId)
    {
        return doorAlarmLogMapper.deleteDoorAlarmLogByAlarmId(alarmId);
    }

    /**
     * 处理门状态变化，记录报警日志
     * 
     * @param slotNumber 槽号
     * @param alarmType 报警类型（1=电源箱门开，2=槽控机门开）
     * @param isOpen 门是否打开
     * @param doorInfo 门状态信息（用于更新Redis）
     */
    @Override
    public void handleDoorStatusChange(Integer slotNumber, String alarmType, Boolean isOpen, DoorStatusInfo doorInfo)
    {
        try {
            // 构建Redis键
            String redisKey = (alarmType.equals("1") 
                ? DoorAlarmConstants.REDIS_DOOR_POWER_BOX_KEY 
                : DoorAlarmConstants.REDIS_DOOR_CONTROLLER_KEY) + slotNumber;
            
            if (Boolean.TRUE.equals(isOpen)) {
                // 门打开：检查是否已有进行中的报警记录
                Long existingAlarmId = doorInfo != null ? doorInfo.getAlarmId() : null;
                
                if (existingAlarmId == null) {
                    // 没有进行中的报警，先更新Redis状态（快速响应）
                    if (doorInfo == null) {
                        doorInfo = new DoorStatusInfo();
                    }
                    doorInfo.setStatus(true);
                    redisCache.setCacheObject(redisKey, doorInfo);
                    
                    // 异步保存到数据库（避免阻塞监控线程）
                    DoorAlarmLog alarmLog = new DoorAlarmLog();
                    alarmLog.setSlotNumber(slotNumber);
                    alarmLog.setAlarmType(alarmType);
                    // 根据报警类型自动设置报警描述
                    if (alarmType.equals("1")) {
                        alarmLog.setAlarmDescription("电源箱门开");
                    } else if(alarmType.equals("2")) {
                        alarmLog.setAlarmDescription("槽控机门开");
                    }else{
                        alarmLog.setAlarmDescription("");
                    }
                    // 根据槽号查询工区、厂房、段信息
                    WorkshopSlotDTO slotDTO = workshopManagementService.getSlotFromCache(slotNumber);
                    if (slotDTO != null) {
                        alarmLog.setAreaName(slotDTO.getAreaName());
                        alarmLog.setFactoryName(slotDTO.getFactoryName());
                        alarmLog.setSectionName(slotDTO.getSectionName());
                    } else {
                        log.warn("槽号 {} 在缓存中未找到工区信息，将保存为空值", slotNumber);
                    }
                    alarmLog.setStartTime(new Date());
                    alarmLog.setStatus("1"); // 进行中
                    
                    // 异步保存到数据库
                    getSelf().saveAlarmLogAsync(alarmLog, redisKey, doorInfo, slotNumber, alarmType);
                }
            } else {
                // 门关闭：更新报警记录
                Long alarmId = doorInfo != null ? doorInfo.getAlarmId() : null;
                
                if (alarmId != null) {
                    // 先更新Redis状态（快速响应）
                    if (doorInfo != null) {
                        doorInfo.setAlarmId(null);
                        doorInfo.setStatus(false);
                        redisCache.setCacheObject(redisKey, doorInfo);
                    }
                    
                    // 异步更新数据库（避免阻塞监控线程）
                    getSelf().updateAlarmLogAsync(alarmId, slotNumber, alarmType);
                } else {
                    // Redis中没有记录，但门已关闭，可能是异常情况，先更新Redis状态
                    if (doorInfo != null) {
                        doorInfo.setAlarmId(null);
                        doorInfo.setStatus(false);
                        redisCache.setCacheObject(redisKey, doorInfo);
                    }
                    
                    // 异步从数据库查询并修复
                    getSelf().repairAlarmLogAsync(slotNumber, alarmType);
                }
            }
        } catch (Exception e) {
            log.error("处理槽号 {} 的{}门状态变化时发生错误", 
                slotNumber, 
                alarmType.equals("1") ? "电源箱" : "槽控机", 
                e);
        }
    }
    
    /**
     * 异步保存报警记录到数据库
     * 
     * @param alarmLog 报警记录
     * @param redisKey Redis键
     * @param doorInfo 门状态信息
     * @param slotNumber 槽号
     * @param alarmType 报警类型
     */
    @Override
    @Async
    public void saveAlarmLogAsync(DoorAlarmLog alarmLog, String redisKey, DoorStatusInfo doorInfo, 
                                   Integer slotNumber, String alarmType) {
        try {
            // 验证必填字段
            if (alarmLog.getSlotNumber() == null) {
                log.error("保存报警记录失败：槽号为空");
                return;
            }
            if (alarmLog.getAlarmType() == null || alarmLog.getAlarmType().isEmpty()) {
                log.error("保存报警记录失败：报警类型为空");
                return;
            }
            if (alarmLog.getStartTime() == null) {
                log.error("保存报警记录失败：开始时间为空");
                return;
            }
            if (alarmLog.getStatus() == null) {
                log.error("保存报警记录失败：状态为空");
                return;
            }
            
            int result = insertDoorAlarmLog(alarmLog);
            
            if (result > 0 && alarmLog.getAlarmId() != null) {
                // 将报警ID存储到doorInfo并更新Redis
                doorInfo.setAlarmId(alarmLog.getAlarmId());
                redisCache.setCacheObject(redisKey, doorInfo);
                log.info("槽号 {} 的{}门打开，创建报警记录成功，ID: {}", 
                    slotNumber, 
                    alarmType.equals("1") ? "电源箱" : "槽控机",
                    alarmLog.getAlarmId());
                
                // 通过WebSocket推送报警通知
                try {
                    alarmWebSocketService.sendAlarmNotification(alarmLog);
                } catch (Exception e) {
                    log.error("推送报警WebSocket通知失败，报警ID: {}", alarmLog.getAlarmId(), e);
                }
            } else {
                log.error("槽号 {} 的{}门打开，保存报警记录失败：插入结果={}, 报警ID={}", 
                    slotNumber, 
                    alarmType.equals("1") ? "电源箱" : "槽控机",
                    result,
                    alarmLog.getAlarmId());
            }
        } catch (Exception e) {
            log.error("异步保存报警记录时发生错误，槽号: {}, 报警类型: {}", 
                slotNumber, 
                alarmType, 
                e);
        }
    }
    
    /**
     * 异步更新报警记录到数据库
     * 
     * @param alarmId 报警ID
     * @param slotNumber 槽号
     * @param alarmType 报警类型
     */
    @Override
    @Async
    public void updateAlarmLogAsync(Long alarmId, Integer slotNumber, String alarmType) {
        try {
            // 查询报警记录
            DoorAlarmLog alarmLog = selectDoorAlarmLogByAlarmId(alarmId);
            if (alarmLog != null && "1".equals(alarmLog.getStatus())) {
                // 计算持续时间
                Date endTime = new Date();
                long duration = (endTime.getTime() - alarmLog.getStartTime().getTime()) / 1000; // 秒
                
                alarmLog.setEndTime(endTime);
                alarmLog.setDuration(duration);
                alarmLog.setStatus("0"); // 已结束
                alarmLog.setUpdateTime(endTime);
                
                int result = updateDoorAlarmLog(alarmLog);
                if (result > 0) {
                    log.info("槽号 {} 的{}门关闭，结束报警记录，ID: {}，持续时间: {}秒", 
                        slotNumber, 
                        alarmType.equals("1") ? "电源箱" : "槽控机",
                        alarmId,
                        duration);
                    
                    // 通过WebSocket推送报警结束通知
                    try {
                        alarmWebSocketService.sendAlarmEnd(alarmLog);
                    } catch (Exception e) {
                        log.error("推送报警结束WebSocket通知失败，报警ID: {}", alarmId, e);
                    }
                } else {
                    log.error("槽号 {} 的{}门关闭，更新报警记录失败，ID: {}", 
                        slotNumber, 
                        alarmType.equals("1") ? "电源箱" : "槽控机",
                        alarmId);
                }
            }
        } catch (Exception e) {
            log.error("异步更新报警记录时发生错误，槽号: {}, 报警ID: {}", 
                slotNumber, alarmId, e);
        }
    }
    
    /**
     * 异步修复报警记录（从数据库查询并更新）
     * 
     * @param slotNumber 槽号
     * @param alarmType 报警类型
     */
    @Override
    @Async
    public void repairAlarmLogAsync(Integer slotNumber, String alarmType) {
        try {
            DoorAlarmLog activeAlarm = doorAlarmLogMapper.selectActiveAlarmBySlotAndType(slotNumber, alarmType);
            if (activeAlarm != null) {
                // 更新数据库中的记录
                Date endTime = new Date();
                long duration = (endTime.getTime() - activeAlarm.getStartTime().getTime()) / 1000;
                
                activeAlarm.setEndTime(endTime);
                activeAlarm.setDuration(duration);
                activeAlarm.setStatus("0");
                activeAlarm.setUpdateTime(endTime);
                
                updateDoorAlarmLog(activeAlarm);
                log.warn("槽号 {} 的{}门关闭，但Redis中无记录，已从数据库修复报警记录，ID: {}", 
                    slotNumber, 
                    alarmType.equals("1") ? "电源箱" : "槽控机",
                    activeAlarm.getAlarmId());
            }
        } catch (Exception e) {
            log.error("异步修复报警记录时发生错误，槽号: {}, 报警类型: {}", 
                slotNumber, alarmType, e);
        }
    }
}

